home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / lang / p_image1.sit / LSP Source / Edit.p < prev    next >
Encoding:
Text File  |  1989-07-29  |  58.8 KB  |  2,342 lines

  1. unit Edit;
  2.  
  3. {Editing routines used by the Image program}
  4.  
  5. interface
  6.  
  7.     uses
  8.         QuickDraw, OSIntf, PrintTraps, PickerIntf, ToolIntf, globals, Utilities, Graphics, Camera;
  9.  
  10.  
  11.     procedure FlipOrRotate (DoWhat: FlipRotateType);
  12.     procedure DoCopy;
  13.     procedure DoCut;
  14.     procedure DoPaste;
  15.     procedure DoClear;
  16.     procedure ScaleSelection;
  17.     procedure RotateAndScale;
  18.     procedure DoMouseDownInPasteControl (loc: point);
  19.     procedure ShowPasteControl;
  20.     procedure DrawPasteControl;
  21.     procedure ShowClipboard;
  22.     procedure DoObject (obj: ObjectType; event: EventRecord);
  23.     procedure DoAirBrush (event: EventRecord);
  24.     procedure DoBrush (event: EventRecord);
  25.     procedure DoText (loc: point);
  26.     procedure SetAirbrushSize;
  27.     procedure SetBrushSize;
  28.     procedure EditColor;
  29.     procedure UpdateEditMenu;
  30.     procedure ConvertClipboard;
  31.     procedure DeZoom;
  32.     procedure Zoom (event: EventRecord);
  33.     procedure Scroll (event: EventRecord);
  34.     procedure AreaFill (event: EventRecord);
  35.     procedure EditThresholdColor;
  36.     procedure EditExtraColors (entry: integer);
  37.     procedure ZoomImageWindow (var trect: rect);
  38.     procedure DoGrow (WhichWindow: WindowPtr; event: EventRecord);
  39.     procedure DrawCharacter (ch: char);
  40.     procedure GetPictFromScrap;
  41.     function RgnNotTooBig (Rgn1, Rgn2: RgnHandle): boolean;
  42.     procedure SetupOperation (item: integer);
  43.  
  44.  
  45. implementation
  46.  
  47.  
  48.     procedure PivotSelection (var SelectionRect: rect; WindowRect: rect);
  49.         var
  50.             OldWidth, NewWidth, OldHeight, NewHeight, hCenter, vCenter, NewLeft, NewTop: integer;
  51.     begin
  52.         with SelectionRect do begin
  53.                 OldWidth := right - left;
  54.                 OldHeight := bottom - top;
  55.                 hCenter := left + OldWidth div 2;
  56.                 vCenter := top + OldHeight div 2;
  57.             end;
  58.         NewWidth := OldHeight;
  59.         NewHeight := OldWidth;
  60.         NewLeft := hCenter - NewWidth div 2;
  61.         NewTop := vCenter - NewHeight div 2;
  62.         with WindowRect do begin
  63.                 if (NewLeft + NewWidth) > right then
  64.                     NewLeft := right - NewWidth;
  65.                 if (NewTop + NewHeight) > bottom then
  66.                     NewTop := bottom - NewHeight;
  67.                 if NewLeft < 0 then
  68.                     NewLeft := 0;
  69.                 if NewTop < 0 then
  70.                     NewTop := 0;
  71.             end;
  72.         with SelectionRect do begin
  73.                 left := NewLeft;
  74.                 top := NewTop;
  75.                 right := NewLeft + NewWidth;
  76.                 bottom := NewTop + NewHeight;
  77.             end;
  78.     end;
  79.  
  80.  
  81.     procedure FlipLine (var LineBuf: LineType; width: integer);
  82.         var
  83.             TempLine: LineType;
  84.             i, WidthLessOne: integer;
  85.     begin
  86.         TempLine := LineBuf;
  87.         WidthLessOne := width - 1;
  88.         for i := 0 to width - 1 do
  89.             LineBuf[i] := TempLine[WidthLessOne - i];
  90.     end;
  91.  
  92.  
  93.     procedure ScreenToOffscreenRect (var r: rect);
  94.         var
  95.             p1, p2: point;
  96.     begin
  97.         with r do begin
  98.                 p1.h := left;
  99.                 p1.v := top;
  100.                 p2.h := right;
  101.                 p2.v := bottom;
  102.                 ScreenToOffscreen(p1);
  103.                 ScreenToOffscreen(p2);
  104.                 Pt2Rect(p1, p2, r);
  105.             end;
  106.     end;
  107.  
  108.  
  109.     procedure FlipOrRotate; {(DoWhat: FlipRotateType)}
  110.         var
  111.             SaveInfo: InfoPtr;
  112.             width, height, hDst, vSrc, vDst, hSrc, i, inc: integer;
  113.             LineBuf: LineType;
  114.             srect, drect, MaskRect: rect;
  115.             PixelCount: LongInt;
  116.             AutoSelectAll: boolean;
  117.  
  118.     begin
  119.         if NotRectangular or NotInBounds or (UndoBuf = nil) then
  120.             exit(FlipOrRotate);
  121.         if Info^.PicSize > ClipBufSize then begin
  122.                 beep;
  123.                 exit(FlipOrRotate)
  124.             end;
  125.         StopDigitizing;
  126.         AutoSelectAll := not Info^.RoiShowing;
  127.         if AutoSelectAll then
  128.             SelectAll(true);
  129.         ShowWatch;
  130.         if (DoWhat = RotateLeft) or (DoWhat = RotateRight) then
  131.             WhatToUndo := UndoRotate
  132.         else
  133.             WhatToUndo := UndoFlip;
  134.         SetupUndoFromClip;
  135.         SetupUndo;
  136.         UndoInfoRec := info^;
  137.         UndoInfo := @UndoInfoRec;
  138.         with UndoInfo^ do begin
  139.                 PicBaseAddr := UndoBuf;
  140.                 BytesPerRow := PixelsPerLine;
  141.             end;
  142.         SaveInfo := Info;
  143.         srect := info^.osroirect;
  144.         PixelCount := 0;
  145.         case DoWhat of
  146.  
  147.             RotateLeft, RotateRight: 
  148.                 with srect do begin
  149.                         if OptionKeyDown then
  150.                             DoOperation(EraseOp);
  151.                         drect := srect;
  152.                         with info^ do begin
  153.                                 PivotSelection(drect, PicRect);
  154.                                 MaskRect := drect;
  155.                                 OffscreenToScreenRect(MaskRect);
  156.                                 roiRect := MaskRect;
  157.                                 osroiRect := drect;
  158.                                 RectRgn(osRoiRgn, osRoiRect);
  159.                             end;
  160.                         width := right - left;
  161.                         if DoWhat = RotateLeft then begin
  162.                                 hDst := drect.left;
  163.                                 inc := 1
  164.                             end
  165.                         else begin
  166.                                 hDst := drect.right - 1;
  167.                                 inc := -1
  168.                             end;
  169.                         for vSrc := top to bottom - 1 do begin
  170.                                 Info := UndoInfo;
  171.                                 GetLine(left, vSrc, width, LineBuf);
  172.                                 if DoWhat = RotateLeft then
  173.                                     FlipLine(LineBuf, width);
  174.                                 Info := SaveInfo;
  175.                                 PutColumn(hDst, drect.top, width, LineBuf);
  176.                                 hDst := hDst + inc;
  177.                                 PixelCount := PixelCount + width;
  178.                                 if PixelCount > 10000 then begin
  179.                                         UpdateScreen(MaskRect);
  180.                                         PixelCount := 0;
  181.                                     end;
  182.                             end;
  183.                     end;
  184.  
  185.             FlipVertical: 
  186.                 with srect do begin
  187.                         MaskRect := srect;
  188.                         OffscreenToScreenRect(MaskRect);
  189.                         width := right - left;
  190.                         vDst := bottom;
  191.                         for vSrc := top to bottom - 1 do begin
  192.                                 Info := UndoInfo;
  193.                                 GetLine(left, vSrc, width, LineBuf);
  194.                                 Info := SaveInfo;
  195.                                 vDst := vDst - 1;
  196.                                 PutLine(left, vDst, width, LineBuf);
  197.                             end;
  198.                     end;
  199.  
  200.             FlipHorizontal: 
  201.                 with srect do begin
  202.                         MaskRect := srect;
  203.                         OffscreenToScreenRect(MaskRect);
  204.                         width := right - left;
  205.                         for vSrc := top to bottom - 1 do begin
  206.                                 Info := UndoInfo;
  207.                                 GetLine(left, vSrc, width, LineBuf);
  208.                                 FlipLine(LineBuf, width);
  209.                                 Info := SaveInfo;
  210.                                 PutLine(left, vSrc, width, LineBuf);
  211.                                 PixelCount := PixelCount + width;
  212.                                 if PixelCount > 10000 then begin
  213.                                         UpdateScreen(MaskRect);
  214.                                         PixelCount := 0;
  215.                                     end;
  216.                             end;
  217.                     end;
  218.  
  219.         end; {case}
  220.         Info := SaveInfo;
  221.         with info^ do begin
  222.                 UpdatePicWindow;
  223.                 changes := true;
  224.             end;
  225.         SetupRoiRect;
  226.         if AutoSelectAll then
  227.             KillRoi;
  228.     end;
  229.  
  230.  
  231.  
  232.     procedure CopyPicture;
  233.         var
  234.             tPort: GrafPtr;
  235.             err: LongInt;
  236.             line: integer;
  237.             src, dst: ptr;
  238.     begin
  239.         TextOnClip := false;
  240.         with info^ do begin
  241.                 if PicSize > ClipBufSize then begin
  242.                         beep;
  243.                         WhatsOnClip := Nothing;
  244.                         exit(CopyPicture)
  245.                     end;
  246.                 SetupUndo;
  247.                 if PictureType = camera then begin
  248.                         src := PicBaseAddr;
  249.                         dst := ClipBuf;
  250.                         for line := 1 to 480 do begin
  251.                                 BlockMove(src, dst, 640);
  252.                                 src := ptr(ord4(src) + 1024);
  253.                                 dst := ptr(ord4(dst) + 640);
  254.                             end;
  255.                     end
  256.                 else
  257.                     BlockMove(PicBaseAddr, ClipBuf, PicSize);
  258.             end;
  259.         ClipboardConverted := false;
  260.         with ClipBufInfo^ do begin
  261.                 PixelsPerLine := info^.PixelsPerLine;
  262.                 BytesPerRow := info^.PixelsPerLine;
  263.                 nLines := Info^.nLines;
  264.                 RoiRect := info^.roiRect;
  265.                 osroiRect := info^.osroiRect;
  266.                 roiType := Info^.roiType;
  267.                 PicRect := Info^.PicRect;
  268.                 GetPort(tPort);
  269.                 with osPort^.portPixMap^^ do begin
  270.                         RowBytes := BitOr(PixelsPerLine, $8000);
  271.                         bounds := PicRect;
  272.                     end;
  273.                 SetPort(GrafPtr(osPort));
  274.                 with osPort^ do begin
  275.                         PortRect := PicRect;
  276.                         RectRgn(visRgn, PicRect);
  277.                     end;
  278.                 SetPort(tPort);
  279.                 if RoiType = RectRoi then
  280.                     WhatsOnClip := RectPic
  281.                 else
  282.                     WhatsOnClip := NonRectPic;
  283.                 if (info^.PictureType = camera) and (PasteMode = LiveSelection) then
  284.                     PasteMode := PasteFromCamera
  285.                 else
  286.                     PasteMode := NormalPaste;
  287.                 CopyRgn(info^.osroiRgn, osroiRgn);
  288.             end;
  289.     end;
  290.  
  291.  
  292.     procedure CopyWindow;
  293.         var
  294.             tPort: GrafPtr;
  295.             WindowSize: LongInt;
  296.             WindowRect: rect;
  297.             WhichWindow: WindowPtr;
  298.             kind: integer;
  299.     begin
  300.         WhichWindow := FrontWindow;
  301.         WindowRect := WhichWindow^.PortRect;
  302.         kind := WindowPeek(WhichWindow)^.WindowKind;
  303.         with WindowRect do
  304.             WindowSize := LongInt(right) * bottom;
  305.         if kind = LUTKind then
  306.             WindowRect.bottom := 256;
  307.         if kind = ProfilePlotKind then
  308.             ConvertPlotToText;
  309.         if kind = HistoKind then
  310.             ConvertHistoToText;
  311.         if (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) then begin
  312.                 Copying := true;
  313.                 DrawPlot; {Draw without grow box}
  314.                 Copying := false;
  315.             end;
  316.         if WindowSize > ClipBufSize then begin
  317.                 beep;
  318.                 WhatsOnClip := Nothing;
  319.                 exit(CopyWindow)
  320.             end;
  321.         ClipboardConverted := false;
  322.         with ClipBufInfo^ do begin
  323.                 RoiType := RectRoi;
  324.                 RoiRect := WindowRect;
  325.                 osRoiRect := WindowRect;
  326.                 RectRgn(osroiRgn, osroiRect);
  327.                 PicRect := WindowRect;
  328.                 PixelsPerLine := WindowRect.right;
  329.                 BytesPerRow := PixelsPerLine;
  330.                 nLines := WindowRect.bottom;
  331.                 with osPort^.portPixMap^^ do begin
  332.                         RowBytes := BitOr(WindowRect.right, $8000);
  333.                         bounds := WindowRect;
  334.                     end;
  335.                 GetPort(tPort);
  336.                 with osPort^ do begin
  337.                         PortRect := PicRect;
  338.                         RectRgn(visRgn, PicRect);
  339.                         fgColor := BlackC;
  340.                         bkColor := WhiteC;
  341.                     end;
  342.                 WhatsOnClip := RectPic;
  343.                 PasteMode := NormalPaste;
  344.                 SetPort(GrafPtr(osPort));
  345.                 hlock(handle(ClipBufInfo^.osPort^.portPixMap));
  346.                 CopyBits(WhichWindow^.PortBits, BitMapHandle(ClipBufInfo^.osPort^.portPixMap)^^, WindowRect, WindowRect, SrcCopy, nil);
  347.                 hunlock(handle(ClipBufInfo^.osPort^.portPixMap));
  348.                 SetPort(tPort);
  349.             end; {with}
  350.     end;
  351.  
  352.  
  353.     procedure DoCopy;
  354.         var
  355.             err: OSErr;
  356.     begin
  357.         if ScrapNotCleared then begin
  358.                 ScrapNotCleared := false;
  359.                 err := ZeroScrap;
  360.                 OldScrapCount := GetScrapCount;
  361.             end;
  362.         case WhatToCopy of
  363.             CopyColor: 
  364.                 begin
  365.                     ClipColorIndex := CurrentColorIndex;
  366.                     WhatsOnClip := AColor;
  367.                     TextOnClip := false;
  368.                 end;
  369.             CopySelection: 
  370.                 CopyPicture;
  371.             CopyHistogram, CopyPlot, CopyCLUT, CopyGrayMap: 
  372.                 CopyWindow;
  373.             CopyAreas, CopyLengths, CopyPoints: 
  374.                 begin
  375.                     CopyResultsToBuffer;
  376.                     TextOnClip := true
  377.                 end;
  378.             otherwise
  379.                 beep;
  380.         end;
  381.     end;
  382.  
  383.  
  384.     procedure DoCut;
  385.     begin
  386.         DoCopy;
  387.         if info^.RoiShowing then begin
  388.                 CurrentOp := EraseOp;
  389.                 OpPending := true
  390.             end;
  391.     end;
  392.  
  393.  
  394.     procedure PasteColor;
  395.     begin
  396.         with info^ do
  397.             if (CurrentTool = PickerTool) and (LUTMode = ColorPalette) then begin
  398.                     RedX[CurrentColorIndex] := RedX[ClipColorIndex];
  399.                     GreenX[CurrentColorIndex] := GreenX[ClipColorIndex];
  400.                     BlueX[CurrentColorIndex] := BlueX[ClipColorIndex];
  401.                     UpdateColors;
  402.                 end
  403.             else
  404.                 beep;
  405.     end;
  406.  
  407.  
  408.     procedure CenterRect (inRect, outRect: rect; var ResultRect: rect);
  409.         var
  410.             width, height, hcenter, vcenter: integer;
  411.     begin
  412.         with inRect do begin
  413.                 width := right - left;
  414.                 height := bottom - top;
  415.             end;
  416.         with outRect do begin
  417.                 hcenter := left + (right - left) div 2;
  418.                 vcenter := top + (bottom - top) div 2;
  419.             end;
  420.         with ResultRect do begin
  421.                 left := hcenter - width div 2;
  422.                 top := vcenter - height div 2;
  423.                 right := left + width;
  424.                 bottom := top + height;
  425.             end;
  426.     end;
  427.  
  428.  
  429.     procedure PastePicture;
  430.         var
  431.             loc: point;
  432.             width, height, osroiHeight, SrcHeight, PicHeight, dh, dv: integer;
  433.     begin
  434.         if info = NoInfo then begin
  435.                 PutMessage('To be able to paste you must have a document window open.', '', '');
  436.                 exit(PastePicture)
  437.             end;
  438.         if PasteTransferMode <> SrcCopy then begin
  439.                 PasteTransferMode := SrcCopy;
  440.                 if PasteControl <> nil then
  441.                     DrawPasteControl
  442.             end;
  443.         with info^ do begin
  444.                 WhatToUndo := UndoPaste;
  445.                 SetupUndo;
  446.                 if RoiShowing then
  447.                     with RoiRect do {Pasting back into selection of same size?}
  448.                         if ((right - left) = (ClipBufInfo^.RoiRect.right - ClipBufInfo^.RoiRect.left)) and ((bottom - top) = (ClipBufInfo^.RoiRect.bottom - ClipBufInfo^.RoiRect.top)) and (ClipBufInfo^.RoiType = RoiType) then begin
  449.                                 OpPending := true;
  450.                                 CurrentOp := PasteOp;
  451.                                 exit(PastePicture)
  452.                             end;
  453.                 with ClipBufInfo^.osroiRect do {Pasting into same size window?}
  454.                     if (PicRect.right = right - left) and (PicRect.bottom = (bottom - top)) and (ClipBufInfo^.RoiType = RectRoi) then begin
  455.                             SelectAll(true);
  456.                             OpPending := true;
  457.                             CurrentOp := PasteOp;
  458.                             exit(PastePicture)
  459.                         end;
  460.                 if RoiShowing or (roiType <> NoRoi) then
  461.                     KillRoi;
  462.                 CenterRect(ClipBufInfo^.osroiRect, SrcRect, osroiRect);
  463.                 with osroiRect do begin
  464.                         osroiHeight := bottom - top;
  465.                         with srcRect do
  466.                             srcHeight := bottom - top;
  467.                         with PicRect do
  468.                             PicHeight := bottom - top;
  469.                         if (osroiHeight > SrcHeight) and (osroiHeight < PicHeight) and (magnification = 1.0) then begin
  470.                                 top := 0;
  471.                                 bottom := osroiHeight;
  472.                             end;
  473.                     end;
  474.                 roiRect := osroiRect;
  475.                 OffscreenToScreenRect(roiRect);
  476.                 roiType := ClipBufInfo^.roiType;
  477.                 CopyRgn(ClipBufInfo^.osRoiRgn, osRoiRgn);
  478.                 dh := osRoiRect.left - osRoiRgn^^.rgnbbox.left;
  479.                 dv := osRoiRect.top - osRoiRgn^^.rgnbbox.top;
  480.                 OffsetRgn(osroiRgn, dh, dv);
  481.                 RoiShowing := true;
  482.                 OpPending := true;
  483.                 CurrentOp := PasteOp;
  484.                 if PasteMode = PasteFromCamera then
  485.                     ResetQuickCapture;
  486.             end;{with}
  487.     end;
  488.  
  489.  
  490.     procedure GetPictFromScrap;
  491.   {Converts system scrape to local scrape.}
  492.         var
  493.             phandle: handle;
  494.             offset, length, size: LongInt;
  495.             pframe: rect;
  496.             width, height: integer;
  497.             tPort: GrafPtr;
  498.             ScrapInfo: PScrapStuff;
  499.     begin
  500.         ScrapInfo := InfoScrap;
  501.         if ScrapInfo^.ScrapSize <= 0 then
  502.             exit(GetPictFromScrap);
  503.         phandle := NewHandle(0);
  504.         length := GetScrap(phandle, 'PICT', offset);
  505.         if length >= 0 then begin
  506.                 ShowWatch;
  507.                 pframe := PicHandle(phandle)^^.PicFrame;
  508.                 with pframe do begin
  509.                         width := right - left;
  510.                         height := bottom - top;
  511.                         size := LongInt(width) * height;
  512.                         if size > ClipBufSize then begin
  513.                                 PutMessage('Sorry, but this picture is too large to paste.', '', '');
  514.                                 DisposHandle(phandle);
  515.                                 exit(GetPictFromScrap)
  516.                             end;
  517.                     end;
  518.                 with ClipBufInfo^ do begin
  519.                         PixelsPerLine := width;
  520.                         nlines := height;
  521.                         SetRect(PicRect, 0, 0, width, height);
  522.                         osroiRect := PicRect;
  523.                         RectRgn(osroiRgn, osRoiRect);
  524.                         RoiType := Rectroi;
  525.                         GetPort(tPort);
  526.                         SetPort(GrafPtr(osPort));
  527.                         BytesPerRow := PixelsPerLine;
  528.                         with osPort^.portPixMap^^ do begin
  529.                                 RowBytes := BitOr(PixelsPerLine, $8000);
  530.                                 bounds := PicRect;
  531.                             end;
  532.                         with CGrafPort(osPort^) do begin
  533.                                 PortRect := PicRect;
  534.                                 RectRgn(visRgn, PicRect);
  535.                             end;
  536.                         osPort^.fgColor := WhiteC;
  537.                         osPort^.bkColor := BlackC;
  538.                         PaintRect(PicRect);
  539.                         DrawPicture(PicHandle(phandle), PicRect);
  540.                         DisposHandle(phandle);
  541.                         SetPort(tPort);
  542.                     end;
  543.                 WhatsOnClip := ImportedPic;
  544.                 PasteMode := NormalPaste
  545.             end;
  546.         DisposHandle(phandle);
  547.     end;
  548.  
  549.  
  550.     procedure DoPaste;
  551.         var
  552.             NewScrapCount: integer;
  553.     begin
  554.         NewScrapCount := GetScrapCount;
  555.         if NewScrapCount <> OldScrapCount then begin
  556.                 WhatsOnClip := Nothing;
  557.                 OldScrapCount := NewScrapCount;
  558.             end;
  559.         case WhatsOnClip of
  560.             AColor: 
  561.                 PasteColor;
  562.             RectPic, NonRectPic, ImportedPic: 
  563.                 PastePicture;
  564.             Nothing: 
  565.                 begin
  566.                     GetPictFromScrap;
  567.                     if WhatsOnClip = ImportedPic then
  568.                         PastePicture
  569.                     else
  570.                         beep;
  571.                 end;
  572.         end;
  573.     end;
  574.  
  575.  
  576.     procedure EditExtraColors; {(entry: integer)}
  577.         var
  578.             where: point;
  579.             inRGBColor, OutRGBColor: RGBColor;
  580.     begin
  581.         if (entry <> WhiteC) and (entry <> BlackC) then begin
  582.                 inRGBColor := ExtraColors[entry];
  583.                 outRGBColor := inRGBColor;
  584.                 where.h := 0;
  585.                 where.v := 0;
  586.                 InitCursor;
  587.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then
  588.                     with info^ do begin
  589.                             ExtraColors[entry] := OutRGBColor;
  590.                             changes := true;
  591.                             LoadLUT(cTable);
  592.                         end
  593.             end
  594.         else
  595.             PutMessage('Sorry, but you can not edit white or black.', '', '');
  596.     end;
  597.  
  598.  
  599.     procedure DoClear;
  600.     begin
  601.         if not NoSelection then begin
  602.                 WhatToUndo := UndoClear;
  603.                 SetupUndo;
  604.                 CurrentOp := EraseOp;
  605.                 OpPending := true
  606.             end;
  607.     end;
  608.  
  609.  
  610.     procedure ScaleSelection;
  611.         var
  612.             percent, i, j, NewWidth, NewHeight: integer;
  613.             scale: extended;
  614.     begin
  615.         if NoSelection or NotRectangular or NotInBounds then
  616.             exit(ScaleSelection);
  617.         if OpPending then begin
  618.                 OpPending := false;
  619.                 DoOperation(CurrentOp);
  620.             end;
  621.         DoCopy;
  622.         percent := GetInt('Precent Reduction(10-1000):', 50);
  623.         if (percent >= 10) and (percent <= 1000) then begin
  624.                 scale := percent / 100.0;
  625.                 DoOperation(EraseOp);
  626.                 UpdateScreen(info^.roiRect);
  627.                 info^.RoiShowing := true;
  628.                 PasteTransferMode := SrcCopy;
  629.                 if PasteControl <> nil then
  630.                     DrawPasteControl;
  631.                 DoPaste;
  632.                 with info^.osroiRect do begin
  633.                         NewWidth := round((right - left) * scale);
  634.                         NewHeight := round((bottom - top) * scale);
  635.                         left := left + (right - left - NewWidth) div 2;
  636.                         top := top + (bottom - top - NewHeight) div 2;
  637.                         right := left + NewWidth;
  638.                         bottom := top + NewHeight;
  639.                     end;
  640.                 with info^ do begin
  641.                         RectRgn(osroiRgn, osroiRect);
  642.                         RoiRect := osroiRect;
  643.                         OffscreenToScreenRect(RoiRect);
  644.                     end;
  645.                 UndoFromClip := true;
  646.                 WhatsOnClip := nothing;
  647.                 WhatToUndo := UndoScale;
  648.             end;
  649.     end;
  650.  
  651.  
  652.     procedure GetAngleAndScale (var angle, hscale, vscale: extended);
  653.         const
  654.             AngleID = 3;
  655.             hScaleID = 4;
  656.             vScaleID = 5;
  657.         var
  658.             mylog: DialogPtr;
  659.             item, i: integer;
  660.     begin
  661.         InitCursor;
  662.         mylog := GetNewDialog(50, nil, pointer(-1));
  663.         angle := 45.0;
  664.         hscale := 1.0;
  665.         vscale := 1.0;
  666.         SetDReal(MyLog, AngleID, angle, 1);
  667.         SelIText(MyLog, AngleID, 0, 32767);
  668.         SetDReal(MyLog, hScaleID, hscale, 1);
  669.         SetDReal(MyLog, vScaleID, vscale, 1);
  670.         OutlineButton(MyLog, ok, 16);
  671.         repeat
  672.             ModalDialog(nil, item);
  673.             if item = AngleID then begin
  674.                     angle := GetDReal(MyLog, AngleID);
  675.                     if angle > 180.0 then
  676.                         angle := 180.0;
  677.                     if angle < -180.0 then
  678.                         angle := -180.0;
  679.                 end;
  680.             if item = hScaleID then begin
  681.                     hscale := GetDReal(MyLog, hScaleID);
  682.                     if hscale > 10.0 then
  683.                         hscale := 100.0;
  684.                     if hscale < 0.1 then
  685.                         hscale := 0.1;
  686.                 end;
  687.             if item = vScaleID then begin
  688.                     vscale := GetDReal(MyLog, vScaleID);
  689.                     if vscale > 10.0 then
  690.                         vscale := 10.0;
  691.                     if vscale < 0.1 then
  692.                         vscale := 0.1;
  693.                 end;
  694.         until (item = ok) or (item = cancel);
  695.         DisposDialog(mylog);
  696.         if item = cancel then
  697.             hscale := 0;
  698.     end;
  699.  
  700.  
  701.     procedure RotateAndScale;
  702.         const
  703.             pi = 3.14159;
  704.         type
  705.             radians = real;
  706.             EraseType = (Erase, DontErase);
  707.         var
  708.             angle, CosAngle, SinAngle, htemp, vtemp, h, v, hscale, vscale: extended;
  709.             hloc, vloc, value, width, height, hstart, vstart, hend, vend: integer;
  710.             hfraction, vfraction, UpperAverage, LowerAverage: extended;
  711.             LowerLeft, LowerRight, UpperLeft, UpperRight, hCenter, vCenter: integer;
  712.             hRel, vRel, hbase, vbase, OldWidth, OldHeight: integer;
  713.             SaveInfo: InfoPtr;
  714.             AutoSelectAll, UseNearestNeighbor, DoScaling: boolean;
  715.             MaskRect: rect;
  716.     begin
  717.         if NotRectangular or NotInBounds then
  718.             exit(RotateAndScale);
  719.         if Info^.PicSize > ClipBufSize then begin
  720.                 beep;
  721.                 exit(RotateAndScale)
  722.             end;
  723.         StopDigitizing;
  724.         with info^ do
  725.             UseNearestNeighbor := OptionKeyDown or (LutMode = custom) or (LutMode = AppleDefault);
  726.         GetAngleAndScale(angle, hscale, vscale);
  727.         if hscale = 0.0 then
  728.             exit(RotateAndScale);
  729.         UpdatePicWindow;
  730.         DrawTools;
  731.         AutoSelectAll := not Info^.RoiShowing;
  732.         if AutoSelectAll then
  733.             SelectAll(true);
  734.         ShowWatch;
  735.         WhatToUndo := UndoRotate;
  736.         SetupUndoFromClip;
  737.         SetupUndo;
  738.         UndoInfoRec := info^;
  739.         UndoInfo := @UndoInfoRec;
  740.         with UndoInfo^ do begin
  741.                 PicBaseAddr := UndoBuf;
  742.                 BytesPerRow := PixelsPerLine;
  743.             end;
  744.         SaveInfo := Info;
  745.         angle := -((angle + 270.0) / 360.0) * 2.0 * pi;
  746.         CosAngle := cos(angle);
  747.         SinAngle := sin(angle);
  748.         with info^.osroiRect, info^ do begin
  749.                 width := right - left;
  750.                 height := bottom - top;
  751.                 hCenter := left + (width div 2);
  752.                 vCenter := top + (height div 2);
  753.                 if hscale <> 1.0 then begin
  754.                         OldWidth := width;
  755.                         width := round(width * hscale);
  756.                         if width > PicRect.right then
  757.                             width := PicRect.right;
  758.                         left := left - (width - OldWidth) div 2;
  759.                         if left < 0 then
  760.                             left := 0;
  761.                         if (left + width) > PicRect.right then
  762.                             width := PicRect.right - left;
  763.                         right := left + width;
  764.                         roiRect := osRoiRect;
  765.                         OffscreenToScreenRect(roiRect);
  766.                         RectRgn(osRoiRgn, osRoiRect);
  767.                     end;
  768.                 if vscale <> 1.0 then begin
  769.                         OldHeight := height;
  770.                         height := round(height * vscale);
  771.                         if height > PicRect.bottom then
  772.                             height := PicRect.bottom;
  773.                         top := top - (height - OldHeight) div 2;
  774.                         if top < 0 then
  775.                             top := 0;
  776.                         if (top + height) > PicRect.bottom then
  777.                             height := PicRect.bottom - top;
  778.                         bottom := top + height;
  779.                         roiRect := osRoiRect;
  780.                         OffscreenToScreenRect(roiRect);
  781.                         RectRgn(osRoiRgn, osRoiRect);
  782.                     end;
  783.                 hStart := left;
  784.                 vStart := top;
  785.                 hend := hstart + width - 1;
  786.                 vend := vstart + height - 1;
  787.             end;
  788.         DoScaling := (hscale <> 0.0) or (vscale <> 0.0);
  789.         for vloc := vStart to vEnd do begin
  790.                 for hloc := hStart to hEnd do begin
  791.                         hrel := hloc - hCenter;
  792.                         vrel := vloc - vCenter;
  793.                         htemp := hrel * SinAngle + vrel * CosAngle;
  794.                         vtemp := vrel * SinAngle - hrel * CosAngle;
  795.                         if DoScaling then begin
  796.                                 htemp := htemp / hscale;
  797.                                 vtemp := vtemp / vscale;
  798.                             end;
  799.                         h := htemp + hCenter;
  800.                         v := vtemp + vCenter;
  801.                         info := UndoInfo;
  802.                         if UseNearestNeighbor then
  803.                             value := MyGetPixel(round(h), round(v))
  804.                         else begin {Use bilinear interpolation}
  805.                                 hbase := trunc(h);
  806.                                 vbase := trunc(v);
  807.                                 hFraction := h - hbase;
  808.                                 vFraction := v - vbase;
  809.                                 LowerLeft := MyGetPixel(hbase, vbase);
  810.                                 LowerRight := MyGetPixel(hbase + 1, vbase);
  811.                                 UpperRight := MyGetPixel(hbase + 1, vbase + 1);
  812.                                 UpperLeft := MyGetPixel(hbase, vbase + 1);
  813.                                 UpperAverage := UpperLeft + hfraction * (UpperRight - UpperLeft);
  814.                                 LowerAverage := LowerLeft + hfraction * (LowerRight - LowerLeft);
  815.                                 value := round(LowerAverage + vfraction * (UpperAverage - LowerAverage));
  816.                             end;
  817.                         Info := SaveInfo;
  818.                         PutPixel(hloc, vloc, value);
  819.                     end;
  820.                 SetRect(MaskRect, hstart, vloc, hend, vloc + 1);
  821.                 OffscreenToScreenRect(MaskRect);
  822.                 UpdateScreen(MaskRect);
  823.                 if CommandPeriod then begin
  824.                         UpdateScreen(info^.roiRect);
  825.                         beep;
  826.                         SetupRoiRect;
  827.                         if AutoSelectAll then
  828.                             KillRoi;
  829.                         exit(RotateAndScale)
  830.                     end;
  831.             end;
  832.         with info^ do
  833.             changes := true;
  834.         SetupRoiRect;
  835.         if AutoSelectAll then
  836.             KillRoi;
  837.     end;
  838.  
  839.  
  840.     procedure DoMath;
  841.         const
  842.             PixelsPerUpdate = 15000;
  843.         var
  844.             nrows, ncols, hSrcStart, vSrcStart, hDstStart, vDstStart: integer;
  845.             SaveInfo: InfoPtr;
  846.             h, v, vDst, PixelCount, offset: integer;
  847.             Src, Dst: LineType;
  848.             tmp, range, min, max: LongInt;
  849.             x, xmax, xmin, xrange, xscale: extended;
  850.     begin
  851.         ShowWatch;
  852.         OpPending := false;
  853.         WhatToUndo := UndoPaste;
  854.         KillRoi;
  855.         with info^.osroiRect do begin
  856.                 ncols := right - left;
  857.                 nrows := bottom - top;
  858.                 hDstStart := left;
  859.                 vDstStart := top;
  860.             end;
  861.         with ClipBufInfo^.osroiRect do begin
  862.                 hSrcStart := left;
  863.                 vSrcStart := top;
  864.             end;
  865.         if hDstStart < 0 then begin
  866.                 offset := -hDstStart;
  867.                 hDstStart := 0;
  868.                 hSrcStart := hSrcStart + offset;
  869.                 ncols := ncols - offset;
  870.             end;
  871.         if vDstStart < 0 then begin
  872.                 offset := -vDstStart;
  873.                 vDstStart := 0;
  874.                 vSrcStart := vSrcStart + offset;
  875.                 nrows := nrows - offset;
  876.             end;
  877.         with info^.PicRect do begin
  878.                 if hDstStart + ncols > right then
  879.                     ncols := right - hDstStart;
  880.                 if vDstStart + nrows > bottom then
  881.                     nrows := bottom - vDstStart;
  882.             end;
  883.         SaveInfo := info;
  884.         vDst := vDstStart;
  885.         min := 999999;
  886.         max := -999999;
  887.         xmin := 999999.0;
  888.         xmax := -999999.0;
  889.        {First pass to find result range}
  890.         for v := vSrcStart to vSrcStart + nRows - 1 do begin
  891.                 Info := ClipBufInfo;
  892.                 GetLine(hSrcStart, v, nCols, Src);
  893.                 Info := SaveInfo;
  894.                 GetLine(hDstStart, vDst, nCols, Dst);
  895.                 case CurrentOp of
  896.                     AddOp: 
  897.                         begin
  898.                             for h := 0 to nCols - 1 do begin
  899.                                     tmp := Src[h] + Dst[h];
  900.                                     if tmp > max then
  901.                                         max := tmp;
  902.                                     if tmp < Min then
  903.                                         min := tmp;
  904.                                 end;
  905.                         end;
  906.                     SubtractOp: 
  907.                         begin
  908.                             for h := 0 to nCols - 1 do begin
  909.                                     tmp := Dst[h] - Src[h];
  910.                                     if tmp > max then
  911.                                         max := tmp;
  912.                                     if tmp < Min then
  913.                                         min := tmp;
  914.                                 end;
  915.                         end;
  916.                     MultiplyOp: 
  917.                         begin
  918.                             for h := 0 to nCols - 1 do begin
  919.                                     tmp := LongInt(Dst[h]) * Src[h];
  920.                                     if tmp > max then
  921.                                         max := tmp;
  922.                                     if tmp < min then
  923.                                         min := tmp;
  924.                                 end;
  925.                         end;
  926.                     DivideOp: 
  927.                         begin
  928.                             for h := 0 to nCols - 1 do begin
  929.                                     tmp := Src[h];
  930.                                     if tmp = 0 then
  931.                                         tmp := 1;
  932.                                     x := Dst[h] / tmp;
  933.                                     if x > xmax then begin
  934.                                             xmax := x;
  935.                                         end;
  936.                                     if x < xmin then
  937.                                         xmin := x;
  938.                                 end;
  939.                         end;
  940.                 end;
  941.                 vDst := vDst + 1;
  942.             end;
  943.         vDst := vDstStart;
  944.         if CurrentOp = DivideOp then begin
  945.                 xrange := xmax - xmin;
  946.                 if xrange <> 0.0 then
  947.                     xscale := 256.0 / xrange
  948.                 else
  949.                     xscale := 1;
  950.             end
  951.         else
  952.             range := max - min;
  953.         PixelCount := 0;
  954.        {Second pass to do arithmetic and scaling}
  955.         for v := vSrcStart to vSrcStart + nRows - 1 do begin
  956.                 Info := ClipBufInfo;
  957.                 GetLine(hSrcStart, v, nCols, Src);
  958.                 Info := SaveInfo;
  959.                 GetLine(hDstStart, vDst, nCols, Dst);
  960.                 case CurrentOp of
  961.                     AddOp: 
  962.                         begin
  963.                             for h := 0 to nCols - 1 do begin
  964.                                     tmp := Dst[h] + Src[h] - min;
  965.                                     if range <> 0 then
  966.                                         tmp := tmp * 256 div range
  967.                                     else
  968.                                         tmp := BackgroundColor;
  969.                                     if tmp > 255 then
  970.                                         dst[h] := 255
  971.                                     else
  972.                                         dst[h] := tmp;
  973.                                 end;
  974.                         end;
  975.                     SubtractOp: 
  976.                         begin
  977.                             for h := 0 to nCols - 1 do begin
  978.                                     tmp := Dst[h] - Src[h] - min;
  979.                                     if range <> 0 then
  980.                                         tmp := tmp * 256 div range
  981.                                     else
  982.                                         tmp := BackgroundColor;
  983.                                     if tmp > 255 then
  984.                                         dst[h] := 255
  985.                                     else
  986.                                         dst[h] := tmp;
  987.                                 end;
  988.                         end;
  989.                     MultiplyOp: 
  990.                         begin
  991.                             for h := 0 to nCols - 1 do begin
  992.                                     tmp := LongInt(Dst[h]) * Src[h] - min;
  993.                                     if range <> 0 then
  994.                                         tmp := tmp * 256 div range
  995.                                     else
  996.                                         tmp := BackgroundColor;
  997.                                     if tmp > 255 then
  998.                                         dst[h] := 255
  999.                                     else
  1000.                                         dst[h] := tmp;
  1001.                                 end;
  1002.                         end;
  1003.                     DivideOp: 
  1004.                         begin
  1005.                             for h := 0 to nCols - 1 do begin
  1006.                                     tmp := Src[h];
  1007.                                     if tmp = 0 then
  1008.                                         tmp := 1;
  1009.                                     x := Dst[h] / tmp - xmin;
  1010.                                     if xrange <> 0.0 then
  1011.                                         tmp := trunc(x * xscale)
  1012.                                     else
  1013.                                         tmp := BackgroundColor;
  1014.                                     if tmp > 255 then
  1015.                                         tmp := 255;
  1016.                                     if tmp < 0 then
  1017.                                         tmp := 0;
  1018.                                     dst[h] := tmp;
  1019.                                 end;
  1020.                         end
  1021.                 end;
  1022.                 PutLine(hDstStart, vDst, nCols, Dst);
  1023.                 vDst := vDst + 1;
  1024.                 PixelCount := PixelCount + ncols;
  1025.                 if PixelCount > PixelsPerUpdate then begin
  1026.                         UpdateScreen(info^.roiRect);
  1027.                         if CommandPeriod then begin
  1028.                                 UpdateScreen(info^.roiRect);
  1029.                                 beep;
  1030.                                 exit(DoMath)
  1031.                             end;
  1032.                         PixelCount := 0;
  1033.                     end;
  1034.             end;
  1035.         UpdateScreen(info^.RoiRect);
  1036.     end;
  1037.  
  1038.  
  1039.     procedure DoMouseDownInPasteControl; {(loc:point)}
  1040.         var
  1041.             tPort, tPort2: GrafPtr;
  1042.             nItem, i: integer;
  1043.             BlendColor: rgbColor;
  1044.  
  1045.         procedure InvertItem;
  1046.         begin
  1047.             with pcItem[nitem] do
  1048.                 if iType = pcButton then
  1049.                     InvertRoundRect(r, 6, 6)
  1050.                 else
  1051.                     InvertOval(r);
  1052.         end;
  1053.  
  1054.     begin
  1055.         GetPort(tPort);
  1056.         SetPort(PasteControl);
  1057.         GlobalToLocal(loc);
  1058.         nItem := 0;
  1059.         for i := 1 to npcItems do
  1060.             if PtInRect(loc, pcItem[i].r) then
  1061.                 nitem := i;
  1062.         if nItem > 0 then begin
  1063.                 InvertItem;
  1064.                 while Button and (nitem > 0) do begin
  1065.                         GetMouse(loc);
  1066.                         if not PtInRect(loc, pcItem[nitem].r) then begin
  1067.                                 InvertItem;
  1068.                                 nItem := 0;
  1069.                             end;
  1070.                     end;
  1071.             end;
  1072.         repeat
  1073.         until not button;
  1074.         if nItem > 0 then
  1075.             with pcItem[nitem] do begin
  1076.                     InvertItem;
  1077.                     case nItem of
  1078.                         1: 
  1079.                             PasteTransferMode := SrcCopy;
  1080.                         2: 
  1081.                             PasteTransferMode := SrcOr;
  1082.                         3: 
  1083.                             PasteTransferMode := SrcXor;
  1084.                         4: 
  1085.                             begin
  1086.                                 GetPort(tPort2);
  1087.                                 with BlendColor do begin
  1088.                                         red := 32767;
  1089.                                         blue := 32767;
  1090.                                         green := 32767;
  1091.                                     end;
  1092.                                 SetPort(GrafPtr(info^.osPort));
  1093.                                 OpColor(BlendColor);
  1094.                                 SetPort(tPort2);
  1095.                                 PasteTransferMode := blend;
  1096.                             end;
  1097.                         5, 6, 7, 8: 
  1098.                             if OpPending and (CurrentOp = PasteOp) and (info^.RoiType = RectRoi) then begin
  1099.                                     case nitem of
  1100.                                         5: 
  1101.                                             CurrentOp := AddOp;
  1102.                                         6: 
  1103.                                             CurrentOp := SubtractOp;
  1104.                                         7: 
  1105.                                             CurrentOp := MultiplyOp;
  1106.                                         8: 
  1107.                                             CurrentOp := DivideOp;
  1108.                                     end;
  1109.                                     DoMath;
  1110.                                 end;
  1111.                     end;
  1112.                 end;
  1113.         SetPort(tPort);
  1114.         DrawPasteControl;
  1115.     end;
  1116.  
  1117.  
  1118.     procedure DrawPasteControl;
  1119.         const
  1120.             bWidth = 64;
  1121.             bHeight = 14;
  1122.             rbWidth = 12;
  1123.             rbInnerWidth = 5;
  1124.             rbhloc = 6;
  1125.             rbvloc = 6;
  1126.             vinc = 17;
  1127.             bhloc = 75;
  1128.             bvloc = 6;
  1129.         var
  1130.             tPort: GrafPtr;
  1131.             i, hloc, vloc, SetItem: integer;
  1132.             tType: pcItemType;
  1133.             tRect: rect;
  1134.     begin
  1135.         GetPort(tPort);
  1136.         SetPort(PasteControl);
  1137.         hloc := rbhloc;
  1138.         vloc := rbvloc;
  1139.         tType := pcRadioButton;
  1140.         with PcItem[1] do begin
  1141.                 SetRect(r, hloc, vloc, hloc + rbWidth, vloc + rbWidth);
  1142.                 itype := tType;
  1143.                 str := 'Copy';
  1144.             end;
  1145.         vloc := vloc + vinc;
  1146.         with pcItem[2] do begin
  1147.                 SetRect(r, hloc, vloc, hloc + rbWidth, vloc + rbWidth);
  1148.                 itype := tType;
  1149.                 str := 'Or';
  1150.             end;
  1151.         vloc := vloc + vinc;
  1152.         with pcItem[3] do begin
  1153.                 SetRect(r, hloc, vloc, hloc + rbWidth, vloc + rbWidth);
  1154.                 itype := tType;
  1155.                 str := 'Xor';
  1156.             end;
  1157.         vloc := vloc + vinc;
  1158.         with pcItem[4] do begin
  1159.                 SetRect(r, hloc, vloc, hloc + rbWidth, vloc + rbWidth);
  1160.                 itype := tType;
  1161.                 str := 'Blend';
  1162.             end;
  1163.         hloc := bhloc;
  1164.         vloc := bvloc;
  1165.         tType := pcButton;
  1166.         with pcItem[5] do begin
  1167.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  1168.                 itype := tType;
  1169.                 str := 'Add';
  1170.             end;
  1171.         vloc := vloc + vinc;
  1172.         with pcItem[6] do begin
  1173.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  1174.                 itype := tType;
  1175.                 str := 'Subtract';
  1176.             end;
  1177.         vloc := vloc + vinc;
  1178.         with pcItem[7] do begin
  1179.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  1180.                 itype := tType;
  1181.                 str := 'Multiply';
  1182.             end;
  1183.         vloc := vloc + vinc;
  1184.         with pcItem[8] do begin
  1185.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  1186.                 itype := tType;
  1187.                 str := 'Divide';
  1188.             end;
  1189.         TextFont(SystemFont);
  1190.         TextSize(12);
  1191.         case PasteTransferMode of
  1192.             SrcCopy: 
  1193.                 SetItem := 1;
  1194.             SrcOr: 
  1195.                 SetItem := 2;
  1196.             SrcXor: 
  1197.                 SetItem := 3;
  1198.             Blend: 
  1199.                 SetItem := 4;
  1200.         end;
  1201.         for i := 1 to npcItems do
  1202.             with pcItem[i] do
  1203.                 if iType = pcRadioButton then begin
  1204.                         EraseOval(r);
  1205.                         FrameOval(r);
  1206.                         if i = SetItem then begin
  1207.                                 tRect := r;
  1208.                                 InsetRect(tRect, 3, 3);
  1209.                                 PaintOval(tRect);
  1210.                             end;
  1211.                         MoveTo(r.left + rbWidth + 4, r.top + rbWidth - 2);
  1212.                         DrawString(str);
  1213.                     end
  1214.                 else begin
  1215.                         FrameRoundRect(r, 6, 6);
  1216.                         with r do
  1217.                             MoveTo(left + ((right - left) - StringWidth(str)) div 2, bottom - 3);
  1218.                         DrawString(str);
  1219.                     end;
  1220.         SetPort(tPort);
  1221.     end;
  1222.  
  1223.  
  1224.     procedure ShowPasteControl;
  1225.         const
  1226.             pcwidth = 148;
  1227.             pcheight = 75;
  1228.         var
  1229.             tPort: GrafPtr;
  1230.             blend: RGBColor;
  1231.             trect: rect;
  1232.             wp: ^WindowPtr;
  1233.     begin
  1234.         SetRect(trect, ScreenWidth - pcwidth - 10, ScreenHeight - pcheight - 10, ScreenWidth - 10, ScreenHeight - 10);
  1235.         PasteControl := NewWindow(nil, trect, 'Paste Control', true, rDocProc, nil, true, 0);
  1236.         WindowPeek(PasteControl)^.WindowKind := PasteControlKind;
  1237.         wp := pointer(GhostWindow);
  1238.         wp^ := PasteControl;
  1239.         SetMenuItem(GetMHandle(WindowsMenu), 9, true);
  1240.     end;
  1241.  
  1242.  
  1243.     procedure ShowClipboard;
  1244.         var
  1245.             width, height, hstart, vstart, i, NewScrapCount: integer;
  1246.     begin
  1247.         NewScrapCount := GetScrapCount;
  1248.         if NewScrapCount <> OldScrapCount then begin
  1249.                 WhatsOnClip := Nothing;
  1250.                 OldScrapCount := NewScrapCount;
  1251.             end;
  1252.         if WhatsOnClip = Nothing then
  1253.             GetPictFromScrap;
  1254.         if (WhatsOnClip = RectPic) or (WhatsOnClip = NonRectPic) or (WhatsOnClip = ImportedPic) then
  1255.             with ClipBufinfo^.osroiRect do begin
  1256.                     width := right - left;
  1257.                     if odd(width) then
  1258.                         width := Width + 1;
  1259.                     height := bottom - top;
  1260.                     if NewPicWindow('Clipboard', width, height) then begin
  1261.                             PastePicture;
  1262.                             KillRoi;
  1263.                             SetupUndo;
  1264.                             WhatToUndo := NothingToUndo;
  1265.                             info^.changes := false;
  1266.                         end;
  1267.                 end;
  1268.     end;
  1269.  
  1270.  
  1271.     function RgnNotTooBig; {(Rgn1, Rgn2: RgnHandle): boolean}
  1272.     begin
  1273.         RgnNotTooBig := GetHandleSize(handle(Rgn1)) + GetHandleSize(handle(Rgn2)) < 30000
  1274.     end;
  1275.  
  1276.  
  1277.     procedure DoSelection (obj: ObjectType; start, finish: point);
  1278.         var
  1279.             tRect: rect;
  1280.             temp: integer;
  1281.             TempRgn: RgnHandle;
  1282.     begin
  1283.         WhatToUndo := NothingToUndo;
  1284.         Info^.RoiShowing := false;
  1285.         if (start.h = finish.h) or (start.v = finish.v) then
  1286.             exit(DoSelection);
  1287.         if start.h > finish.h then begin
  1288.                 temp := start.h;
  1289.                 start.h := finish.h;
  1290.                 finish.h := temp;
  1291.             end;
  1292.         if start.v > finish.v then begin
  1293.                 temp := start.v;
  1294.                 start.v := finish.v;
  1295.                 finish.v := temp;
  1296.             end;
  1297.         Pt2Rect(start, finish, tRect);
  1298.         ScreenToOffscreenRect(tRect);
  1299.         with info^ do begin
  1300.                 RoiShowing := true;
  1301.                 if SelectionMode <> NewSelection then
  1302.                     TempRgn := NewRgn;
  1303.                 PenNormal;
  1304.                 OpenRgn;
  1305.                 case obj of
  1306.                     SelectionOval: 
  1307.                         begin
  1308.                             FrameOval(tRect);
  1309.                             roiType := OvalRoi;
  1310.                         end;
  1311.                     RoundedRect: 
  1312.                         begin
  1313.                             FrameRoundRect(tRect, OvalSize, OvalSize);
  1314.                             roiType := RoundRectRoi;
  1315.                         end;
  1316.                     SelectionRect: 
  1317.                         begin
  1318.                             FrameRect(tRect);
  1319.                             roiType := RectRoi;
  1320.                         end;
  1321.                 end;
  1322.                 if SelectionMode = NewSelection then
  1323.                     CloseRgn(osroiRgn)
  1324.                 else begin
  1325.                         CloseRgn(TempRgn);
  1326.                         if RgnNotTooBig(osroiRgn, TempRgn) then begin
  1327.                                 if SelectionMode = AddSelection then
  1328.                                     UnionRgn(osroiRgn, TempRgn, osroiRgn)
  1329.                                 else begin
  1330.                                         DiffRgn(osroiRgn, TempRgn, osroiRgn);
  1331.                                         UpdatePicWindow;
  1332.                                     end;
  1333.                             end;
  1334.                         DisposeRgn(TempRgn);
  1335.                         if GetHandleSize(handle(osroiRgn)) = 10 then
  1336.                             roiType := RectRoi
  1337.                         else
  1338.                             roiType := RgnRoi;
  1339.                     end;
  1340.                 osroiRect := osroiRgn^^.rgnBBox;
  1341.                 roiRect := osroiRect;
  1342.                 OffscreenToScreenRect(roiRect);
  1343.             end;{with}
  1344.         measuring := false;
  1345.     end;
  1346.  
  1347.  
  1348.     procedure FindLength (start, finish: point);
  1349.         var
  1350.             length, h1, h2, v1, v2: extended;
  1351.     begin
  1352.         DrawObject(LineObj, start, finish);
  1353.         ScreenToOffscreen(start);
  1354.         ScreenToOffscreen(finish);
  1355.         h1 := start.h;
  1356.         h2 := finish.h;
  1357.         v1 := start.v;
  1358.         v2 := finish.v;
  1359.         if nLengths < MaxLengths then begin
  1360.                 nLengths := nLengths + 1;
  1361.                 UnsavedLengths := UnsavedLengths + 1
  1362.             end
  1363.         else
  1364.             beep;
  1365.         length := sqrt(sqr(h2 - h1) + sqr(v2 - v1));
  1366.         PixelLength := length;
  1367.         with info^ do
  1368.             if scale <> 0.0 then
  1369.                 length := length / scale;
  1370.         lengths[nLengths] := length;
  1371.         TotalLength := TotalLength + length;
  1372.         ShowResults;
  1373.         measuring := true;
  1374.     end;
  1375.  
  1376.  
  1377.     procedure DoObject; {(obj: ObjectType; event: EventRecord)}
  1378.         var
  1379.             Start, Finish, ScreenStart, ScreenFinish, osStart, osFinish: point;
  1380.             r: rect;
  1381.             tPort: GrafPtr;
  1382.             ff, DeltaX, DeltaY, switch, imag: integer;
  1383.             Constrain: boolean;
  1384.     begin
  1385.         if (obj = LengthObj) or (obj = PlotLine) or (obj = LineObj) then
  1386.             ValuesMode := LengthValues
  1387.         else
  1388.             ValuesMode := WidthValues;
  1389.         DrawLabels;
  1390.         start := event.where;
  1391.         osStart := start;
  1392.         ScreenToOffscreen(osStart);
  1393.         finish := start;
  1394.         PenNormal;
  1395.         PenMode(PatXor);
  1396.         with info^ do begin
  1397.                 imag := trunc(magnification + 0.5);
  1398.                 ff := imag div 2;
  1399.                 if (obj = SelectionRect) or (obj = SelectionOval) or (obj = RoundedRect) then
  1400.                     PenSize(imag, imag)
  1401.                 else
  1402.                     PenSize(imag * LineWidth, imag * LineWidth);
  1403.             end;
  1404.         while button do begin
  1405.                 GetMouse(finish);
  1406.                 with finish, Info^ do begin
  1407.                         if h > wrect.right then
  1408.                             h := wrect.right;
  1409.                         if v > wrect.bottom then
  1410.                             v := wrect.bottom;
  1411.                         if h < 0 then
  1412.                             h := 0;
  1413.                         if v < 0 then
  1414.                             v := 0;
  1415.                     end;
  1416.                 if ShiftKeyDown then begin
  1417.                         DeltaX := finish.h - start.h;
  1418.                         DeltaY := finish.v - start.v;
  1419.                         if (obj = lineObj) or (obj = PlotLine) or (obj = LengthObj) then begin
  1420.                                 if abs(DeltaX) > abs(DeltaY) then
  1421.                                     finish.v := start.v
  1422.                                 else
  1423.                                     finish.h := start.h
  1424.                             end
  1425.                         else begin
  1426.                                 if ((DeltaX > 0) and (DeltaY < 0)) or ((DeltaX < 0) and (DeltaY > 0)) then
  1427.                                     switch := -1
  1428.                                 else
  1429.                                     switch := 1;
  1430.                                 if abs(DeltaX) > abs(DeltaY) then
  1431.                                     finish.h := start.h + switch * DeltaY
  1432.                                 else
  1433.                                     finish.v := start.v + switch * DeltaX;
  1434.                             end;
  1435.                     end;
  1436.                 osFinish := finish;
  1437.                 ScreenToOffscreen(osfinish);
  1438.                 case obj of
  1439.                     LineObj, PlotLine, LengthObj: 
  1440.                         begin
  1441.                             MoveTo(start.h - ff, start.v - ff);
  1442.                             LineTo(finish.h - ff, finish.v - ff);
  1443.                             Show3RealValues(abs(osfinish.h - osstart.h), abs(osfinish.v - osstart.v), sqrt(sqr(LongInt(osfinish.h - osstart.h)) + sqr(LongInt(osfinish.v - osstart.v))));
  1444.                             MoveTo(start.h - ff, start.v - ff);
  1445.                             LineTo(finish.h - ff, finish.v - ff);
  1446.                         end;
  1447.                     Rectangle, SelectionRect: 
  1448.                         begin
  1449.                             if obj = SelectionRect then begin
  1450.                                     PatIndex := (PatIndex + 1) mod 8;
  1451.                                     PenPat(pat[PatIndex]);
  1452.                                 end;
  1453.                             Pt2Rect(start, finish, r);
  1454.                             OffsetRect(r, -ff, -ff);
  1455.                             FrameRect(r);
  1456.                             Show2Values(osfinish.h - osstart.h, osfinish.v - osstart.v);
  1457.                             Pt2Rect(start, finish, r);
  1458.                             OffsetRect(r, -ff, -ff);
  1459.                             FrameRect(r);
  1460.                         end;
  1461.                     RoundedRect: 
  1462.                         begin
  1463.                             PatIndex := (PatIndex + 1) mod 8;
  1464.                             PenPat(pat[PatIndex]);
  1465.                             Pt2Rect(start, finish, r);
  1466.                             OffsetRect(r, -ff, -ff);
  1467.                             FrameRoundRect(r, OvalSize, OvalSize);
  1468.                             Show2Values(osfinish.h - osstart.h, osfinish.v - osstart.v);
  1469.                             Pt2Rect(start, finish, r);
  1470.                             OffsetRect(r, -ff, -ff);
  1471.                             FrameRoundRect(r, OvalSize, OvalSize);
  1472.                         end;
  1473.                     SelectionOval: 
  1474.                         begin
  1475.                             PatIndex := (PatIndex + 1) mod 8;
  1476.                             PenPat(pat[PatIndex]);
  1477.                             Pt2Rect(start, finish, r);
  1478.                             OffsetRect(r, -ff, -ff);
  1479.                             FrameOval(r);
  1480.                             Show2Values(osfinish.h - osstart.h, osfinish.v - osstart.v);
  1481.                             Pt2Rect(start, finish, r);
  1482.                             OffsetRect(r, -ff, -ff);
  1483.                             FrameOval(r);
  1484.                         end;
  1485.                 end;
  1486.             end;
  1487.         if obj = PlotLine then begin
  1488.                 DoPlot(event, start, finish);
  1489.                 if OptionKeyDown then
  1490.                     obj := LineObj
  1491.                 else
  1492.                     exit(DoObject)
  1493.             end;
  1494.         case obj of
  1495.             SelectionRect, SelectionOval, RoundedRect: 
  1496.                 DoSelection(obj, start, finish);
  1497.             LengthObj: 
  1498.                 FindLength(start, finish);
  1499.             otherwise
  1500.                 DrawObject(obj, start, finish);
  1501.         end;
  1502.     end;
  1503.  
  1504.  
  1505.     procedure RandowBrushPoint (var xoffset, yoffset: integer);
  1506.     begin
  1507.         repeat
  1508.             xoffset := (random mod AirBrushdiameter + random mod AirBrushdiameter) div 2 - AirBrushRadius;
  1509.             yoffset := (random mod AirBrushDiameter + random mod AirBrushDiameter) div 2 - AirBrushRadius;
  1510.         until xoffset * xoffset + yoffset * yoffset <= AirBrushRadius2;
  1511.     end;
  1512.  
  1513.  
  1514.     procedure DrawAirBrush (xcenter, ycenter: integer);
  1515.         var
  1516.             i, xoff, yoff: integer;
  1517.     begin
  1518.         for i := 1 to 5 * trunc(info^.magnification + 0.5) + 3 do begin
  1519.                 RandowBrushPoint(xoff, yoff);
  1520.                 PutPixel(xcenter + xoff, ycenter + yoff, ForegroundColor);
  1521.             end;
  1522.     end;
  1523.  
  1524.  
  1525.     procedure DoAirBrush; {(event: EventRecord)}
  1526.   {Reference: "Spaying and Smudging", Dick Pountain, Byte, November 1987}
  1527.         var
  1528.             h, xcenter, ycenter, off: integer;
  1529.             MaskRect: rect;
  1530.             pt: point;
  1531.     begin
  1532.         with info^ do begin
  1533.                 changes := true;
  1534.                 off := AirbrushRadius * trunc(magnification + 0.5);
  1535.             end;
  1536.         repeat
  1537.             GetMouse(pt);
  1538.             with MaskRect, pt do begin
  1539.                     left := h - off;
  1540.                     top := v - off;
  1541.                     right := h + off;
  1542.                     bottom := v + off;
  1543.                 end;
  1544.             ScreenToOffscreen(pt);
  1545.             with pt do begin
  1546.                     xcenter := h;
  1547.                     ycenter := v
  1548.                 end;
  1549.             DrawAirbrush(xcenter, ycenter);
  1550.             UpdateScreen(MaskRect);
  1551.         until not button;
  1552.     end;
  1553.  
  1554.  
  1555.     procedure DoBrush; {(event: EventRecord)}
  1556.         var
  1557.             r, ScreenRect: rect;
  1558.             tPort: GrafPtr;
  1559.             p1, p2, p2x, start: point;
  1560.             WhichWindow: WindowPtr;
  1561.             SaveLineWidth, SaveForegroundColor: integer;
  1562.             Constrained, MoreHorizontal, FirstTime: boolean;
  1563.             offset, IntegerMagnification, width: integer;
  1564.     begin
  1565.         SaveLineWidth := LineWidth;
  1566.         p1 := event.where;
  1567.         start := p1;
  1568.         if OptionKeyDown then begin
  1569.                 case CurrentTool of
  1570.                     Brush, Pencil: 
  1571.                         GetForegroundColor(event);
  1572.                     Eraser: 
  1573.                         GetBackgroundColor(event);
  1574.                 end;
  1575.                 if (CurrentTool = Brush) or (CurrentTool = Eraser) then
  1576.                     exit(DoBrush);
  1577.             end;
  1578.         case CurrentTool of
  1579.             Pencil: 
  1580.                 LineWidth := 1;
  1581.             Brush, Eraser: 
  1582.                 begin
  1583.                     IntegerMagnification := trunc(info^.magnification);
  1584.                     if IntegerMagnification < 1 then
  1585.                         IntegerMagnification := 1;
  1586.                     if CurrentTool = Brush then
  1587.                         width := BrushWidth
  1588.                     else
  1589.                         width := 16;
  1590.                     LineWidth := width div IntegerMagnification;
  1591.                     if LineWidth < 1 then
  1592.                         LineWidth := 1;
  1593.                 end;
  1594.         end;
  1595.         with info^ do begin
  1596.                 offset := round(LineWidth * magnification / 2.0);
  1597.                 if magnification >= 2.0 then
  1598.                     offset := offset - 1;
  1599.             end;
  1600.         if CurrentTool <> Pencil then
  1601.             with p1 do begin
  1602.                     h := h - offset;
  1603.                     v := v - offset
  1604.                 end;
  1605.         Constrained := ShiftKeyDown;
  1606.         FirstTime := true;
  1607.         if CurrentTool = eraser then begin
  1608.                 SaveForegroundColor := ForegroundColor;
  1609.                 SetForegroundColor(BackgroundColor)
  1610.             end
  1611.         else
  1612.             SetForegroundColor(ForegroundColor);
  1613.         repeat
  1614.             GetMouse(p2);
  1615.             if CurrentTool <> Pencil then
  1616.                 with p2 do begin
  1617.                         h := h - offset;
  1618.                         v := v - offset
  1619.                     end;
  1620.             if FirstTime then
  1621.                 if not EqualPt(p1, p2) then begin
  1622.                         MoreHorizontal := abs(p2.h - p1.h) >= abs(p2.v - p1.v);
  1623.                         FirstTime := false;
  1624.                     end;
  1625.             if Constrained then
  1626.                 if MoreHorizontal then
  1627.                     p2.v := p1.v
  1628.                 else
  1629.                     p2.h := p1.h;
  1630.             if CurrentTool = brush then
  1631.                 DrawObject(BrushObj, p1, p2)
  1632.             else
  1633.                 DrawObject(LineObj, p1, p2);
  1634.             p1 := p2;
  1635.         until not button;
  1636.         if CurrentTool = Eraser then
  1637.             SetForegroundColor(SaveForegroundColor);
  1638.         LineWidth := SaveLineWidth;
  1639.     end;
  1640.  
  1641.  
  1642.     procedure DrawCharacter; {(ch: char)}
  1643.         var
  1644.             tPort: GrafPtr;
  1645.             p1, p2: point;
  1646.             width: integer;
  1647.             MaskRect: rect;
  1648.             ScreenLoc: point;
  1649.             str: str255;
  1650.     begin
  1651.         if (not IsInsertionPoint) or (Info = NoInfo) then begin
  1652.                 beep;
  1653.                 exit(DrawCharacter)
  1654.             end;
  1655.         if ch = return then
  1656.             with InsertionPoint do begin
  1657.                     h := TextStart.h;
  1658.                     v := v + CurrentSize;
  1659.                     SetupUndo;
  1660.                     TextStr := '';
  1661.                     TextStart := InsertionPoint;
  1662.                     exit(DrawCharacter)
  1663.                 end;
  1664.         GetPort(tPort);
  1665.         SetPort(GrafPtr(Info^.osPort));
  1666.         TextFont(CurrentFontID);
  1667.         TextFace(CurrentStyle);
  1668.         TextSize(CurrentSize);
  1669.         if ch = BackSpace then
  1670.             with InsertionPoint do begin
  1671.                     if length(TextStr) > 0 then begin
  1672.                             delete(TextStr, length(TextStr), 1);
  1673.                             DisplayText;
  1674.                         end;
  1675.                     SetPort(tPort);
  1676.                     exit(DrawCharacter)
  1677.                 end;
  1678.         str := ' '; {Needed for MPW}
  1679.         str[1] := ch;
  1680.         TextStr := Concat(TextStr, str);
  1681.         DisplayText;
  1682.         SetPort(tPort);
  1683.     end;
  1684.  
  1685.  
  1686.     procedure DoText; {(loc: point)}
  1687.         var
  1688.             str: str255;
  1689.             i: integer;
  1690.     begin
  1691.         ScreenToOffscreen(loc);
  1692.         with loc do begin
  1693.                 InsertionPoint.h := h;
  1694.                 InsertionPoint.v := v + 4;
  1695.             end;
  1696.         IsInsertionPoint := true;
  1697.         TextStart := InsertionPoint;
  1698.         TextStr := '';
  1699.         if OptionKeyDown then begin
  1700.                 if nAreas2 > 0 then begin
  1701.                         str := '';
  1702.                         if AreaM in Measurements then
  1703.                             with info^ do begin
  1704.                                     if scale <> 0.0 then
  1705.                                         RealToString(PixelCount[nAreas2] / sqr(scale), 1, 2, str)
  1706.                                     else
  1707.                                         NumToString(PixelCount[nAreas2], str);
  1708.                                 end
  1709.                         else if MeanM in Measurements then
  1710.                             RealToString(Mean[nAreas2], 1, 2, str);
  1711.                         if str <> '' then begin
  1712.                                 if nAreas2 > 0 then
  1713.                                     nAreas2 := nAreas2 - 1;
  1714.                                 for i := 1 to length(str) do
  1715.                                     DrawCharacter(str[i]);
  1716.                             end;
  1717.                     end;
  1718.             end;
  1719.     end;
  1720.  
  1721.  
  1722.     procedure AreaFill; {(event: EventRecord)}
  1723.         var
  1724.             loc: point;
  1725.             MaskBits: BitMap;
  1726.             BitMapSize: LongInt;
  1727.             tPort: GrafPtr;
  1728.             trect: rect;
  1729.     begin
  1730.         ShowWatch;
  1731.         loc := event.where;
  1732.         ScreenToOffscreen(loc);
  1733.         with info^ do begin
  1734.                 tRect := PicRect;
  1735.                 with tRect do
  1736.                     if right mod 8 <> 0 then
  1737.                         right := (right div 16) * 16;
  1738.                 with MaskBits do begin
  1739.                         RowBytes := PixelsPerLine div 8 + 1;
  1740.                         if odd(RowBytes) then
  1741.                             RowBytes := RowBytes + 1;
  1742.                         bounds := tRect;
  1743.                         BitMapSize := LongInt(rowBytes) * nLines;
  1744.                         baseAddr := NewPtr(BitMapSize);
  1745.                         if baseAddr = nil then begin
  1746.                                 beep;
  1747.                                 exit(AreaFill)
  1748.                             end;
  1749.                     end;
  1750.                 GetPort(tPort);
  1751.                 SetPort(GrafPtr(osPort));
  1752.                 SeedCFill(BitMapHandle(osPort^.PortPixMap)^^, MaskBits, tRect, tRect, loc.h, loc.v, nil, 0);
  1753.                 osPort^.fgColor := ForegroundColor;
  1754.                 CopyBits(MaskBits, BitMapHandle(osPort^.PortPixMap)^^, tRect, tRect, SrcOr, nil);
  1755.                 DisposPtr(MaskBits.baseAddr);
  1756.             end;
  1757.         SetPort(tPort);
  1758.         UpdatePicWindow;
  1759.     end;
  1760.  
  1761.  
  1762.     procedure SetAirbrushSize;
  1763.         var
  1764.             TempSize: integer;
  1765.     begin
  1766.         TempSize := GetInt('Airbrush diameter in pixels(1..99):', AirbrushDiameter);
  1767.         if TempSize = -MaxInt then
  1768.             exit(SetAirBrushSize);
  1769.         if (TempSize > 0) and (TempSize < 100) then begin
  1770.                 AirbrushDiameter := TempSize;
  1771.                 AirbrushRadius := AirbrushDiameter div 2;
  1772.                 AirbrushRadius2 := AirbrushRadius * AirBrushRadius
  1773.             end
  1774.         else
  1775.             beep;
  1776.     end;
  1777.  
  1778.  
  1779.     procedure SetBrushSize;
  1780.         var
  1781.             TempSize: integer;
  1782.     begin
  1783.         TempSize := GetInt('Brush Size in pixels(1..99):', BrushWidth);
  1784.         if TempSize = -MaxInt then
  1785.             exit(SetBrushSize);
  1786.         if (TempSize > 0) and (TempSize < 100) then begin
  1787.                 BrushWidth := TempSize;
  1788.                 BrushHeight := BrushWidth
  1789.             end
  1790.         else
  1791.             beep;
  1792.     end;
  1793.  
  1794.  
  1795.     procedure EditColor;
  1796.         var
  1797.             where: point;
  1798.             inRGBColor, OutRGBColor: RGBColor;
  1799.             index: integer;
  1800.     begin
  1801.         with info^ do begin
  1802.                 index := GetColorIndex;
  1803.                 if index = NoColor then
  1804.                     exit(EditColor);
  1805.                 with inRGBColor do begin
  1806.                         red := RedX[index];
  1807.                         green := GreenX[index];
  1808.                         blue := BlueX[index];
  1809.                     end;
  1810.                 outRGBColor := inRGBColor;
  1811.                 where.h := 0;
  1812.                 where.v := 0;
  1813.                 InitCursor;
  1814.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then begin
  1815.                         with outRGBColor do begin
  1816.                                 RedX[index] := red;
  1817.                                 GreenX[index] := green;
  1818.                                 BlueX[index] := blue;
  1819.                             end;
  1820.                         info^.changes := true;
  1821.                     end;
  1822.                 UpdateColors;
  1823.             end; {with}
  1824.     end;
  1825.  
  1826.     procedure EditThresholdColor;
  1827.         var
  1828.             where: point;
  1829.             inRGBColor, OutRGBColor: RGBColor;
  1830.     begin
  1831.         inRGBColor := ThresholdColor;
  1832.         outRGBColor := inRGBColor;
  1833.         where.h := 0;
  1834.         where.v := 0;
  1835.         InitCursor;
  1836.         if GetColor(where, 'Pick a new color...', inRGBColor, outRGBColor) then
  1837.             ThresholdColor := outRGBColor;
  1838.         DrawThreshold;
  1839.     end;
  1840.  
  1841.  
  1842.     procedure FindWhatToCopy;
  1843.         var
  1844.             kind: integer;
  1845.             WhichWindow: WindowPtr;
  1846.     begin
  1847.         WhatToCopy := NothingToCopy;
  1848.         if CurrentTool = PickerTool then
  1849.             WhatToCopy := CopyColor
  1850.         else begin
  1851.                 WhichWindow := FrontWindow;
  1852.                 kind := WindowPeek(WhichWindow)^.WindowKind;
  1853.                 if (kind = PicKind) and measuring then
  1854.                     kind := ResultsKind;
  1855.                 case kind of
  1856.                     PicKind: 
  1857.                         with info^, info^.osroirect do
  1858.                             if RoiShowing and (left >= 0) and (top >= 0) and (right <= PicRect.right) and (bottom <= PicRect.bottom) then
  1859.                                 WhatToCopy := CopySelection;
  1860.                     HistoKind: 
  1861.                         WhatToCopy := CopyHistogram;
  1862.                     ProfilePlotKind, CalibrationPlotKind: 
  1863.                         WhatToCopy := CopyPlot;
  1864.                     LUTKind: 
  1865.                         if info <> NoInfo then
  1866.                             WhatToCopy := CopyCLUT;
  1867.                     GrayMapKind: 
  1868.                         if info <> NoInfo then
  1869.                             WhatToCopy := CopyGrayMap;
  1870.                     ResultsKind: 
  1871.                         if (CurrentTool = ruler) and (nLengths > 0) then
  1872.                             WhatToCopy := CopyLengths
  1873.                         else if (CurrentTool = PointingTool) and (nPoints > 0) then
  1874.                             WhatToCopy := CopyPoints
  1875.                         else if nAreas > 0 then
  1876.                             WhatToCopy := CopyAreas;
  1877.                     otherwise
  1878.                 end;
  1879.             end;
  1880.     end;
  1881.  
  1882.  
  1883.     procedure UpdateEditMenu;
  1884.         var
  1885.             DimUndo, ShowItems: boolean;
  1886.             str: str255;
  1887.             kind, i: integer;
  1888.             WhichWindow: WindowPtr;
  1889.     begin
  1890.         WhichWindow := FrontWindow;
  1891.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1892.         if kind < 0 then begin   {DA is active, so activate Edit menu.}
  1893.                 SetItem(EditMenuH, 1, 'Undo');
  1894.                 SetItem(EditMenuH, 3, 'Cut');
  1895.                 SetItem(EditMenuH, 4, 'Copy');
  1896.                 SetMenuItem(EditMenuH, 1, true);
  1897.                 for i := 3 to 6 do
  1898.                     SetMenuItem(EditMenuH, i, true);
  1899.                 exit(UpdateEditMenu);
  1900.             end;
  1901.         DimUndo := WhatToUndo = NothingToUndo;
  1902.         SetMenuItem(EditMenuH, 1, not DimUndo);
  1903.         if DimUndo then
  1904.             SetItem(EditMenuH, 1, 'Undo');
  1905.         case WhatToUndo of
  1906.             UndoEdit: 
  1907.                 str := 'Editing';
  1908.             UndoFlip: 
  1909.                 str := 'Flip';
  1910.             UndoRotate: 
  1911.                 str := 'Rotate';
  1912.             UndoScale: 
  1913.                 str := 'Scaling';
  1914.             UndoFilter: 
  1915.                 str := 'Filtering';
  1916.             UndoPaste: 
  1917.                 str := 'Paste';
  1918.             UndoMeasurement: 
  1919.                 str := 'Measurement';
  1920.             UndoTransform: 
  1921.                 str := 'Transformation';
  1922.             UndoClear: 
  1923.                 str := 'Clear';
  1924.             UndoContrastEnhancement: 
  1925.                 str := 'Contrast Enhancement';
  1926.             UndoEqualization: 
  1927.                 str := 'Equalization';
  1928.             UndoZoom: 
  1929.                 str := 'Zoom';
  1930.             UndoPlot: 
  1931.                 str := '3D Plot';
  1932.             UndoOutline: 
  1933.                 str := 'Outline';
  1934.             otherwise
  1935.                 str := '';
  1936.         end;
  1937.         SetItem(EditMenuH, 1, concat('Undo ', str));
  1938.         FindWhatToCopy;
  1939.         if WhatToCopy = CopySelection then
  1940.             str := 'Cut Selection'
  1941.         else
  1942.             str := 'Cut';
  1943.         SetItem(EditMenuH, 3, str);
  1944.         SetMenuItem(EditMenuH, 3, WhatToCopy = CopySelection);
  1945.         case WhatToCopy of
  1946.             NothingToCopy: 
  1947.                 str := '';
  1948.             CopySelection: 
  1949.                 str := 'Selection';
  1950.             CopyCLUT: 
  1951.                 str := 'Palette';
  1952.             CopyGrayMap: 
  1953.                 str := 'Gray Map';
  1954.             CopyPlot: 
  1955.                 str := 'Plot';
  1956.             CopyHistogram: 
  1957.                 str := 'Histogram';
  1958.             CopyAreas: 
  1959.                 str := 'Measurements';
  1960.             CopyLengths: 
  1961.                 str := 'Lengths';
  1962.             CopyPoints: 
  1963.                 str := 'Points';
  1964.             CopyColor: 
  1965.                 str := 'Color';
  1966.         end;
  1967.         SetItem(EditMenuH, 4, concat('Copy ', str));
  1968.         SetMenuItem(EditMenuH, 4, WhatToCopy <> NothingToCopy);
  1969.         SetMenuItem(EditMenuH, 6, WhatToCopy = CopySelection);
  1970.         ShowItems := (WhatsOnClip <> nothing) or (OldScrapCount <> GetScrapCount);
  1971.         SetMenuItem(EditMenuH, 5, ShowItems);
  1972.         SetMenuItem(EditMenuH, 22, ShowItems);
  1973.         ShowItems := info <> NoInfo;
  1974.         for i := 8 to 10 do
  1975.             SetMenuItem(EditMenuH, i, ShowItems);
  1976.         for i := 13 to 14 do
  1977.             SetMenuItem(EditMenuH, i, ShowItems);
  1978.         for i := 16 to 20 do
  1979.             SetMenuItem(EditMenuH, i, ShowItems);
  1980.     end;
  1981.  
  1982.  
  1983.     procedure DeZoom;
  1984.         var
  1985.             Width, Height, divisor: integer;
  1986.             OldMagnification: extended;
  1987.     begin
  1988.         with Info^ do begin
  1989.                 if not EqualRect(wrect, savewrect) then begin
  1990.                         UnZoom;
  1991.                         Exit(DeZoom)
  1992.                     end;
  1993.                 if magnification < 2.0 then begin
  1994.                         beep;
  1995.                         exit(DeZoom)
  1996.                     end;
  1997.                 OldMagnification := magnification;
  1998.                 if magnification = 2.0 then begin
  1999.                         magnification := 1.0;
  2000.                         divisor := 4
  2001.                     end
  2002.                 else if magnification = 3.0 then begin
  2003.                         magnification := 2.0;
  2004.                         divisor := 6
  2005.                     end
  2006.                 else if magnification = 4.0 then begin
  2007.                         magnification := 3.0;
  2008.                         divisor := 8
  2009.                     end
  2010.                 else begin
  2011.                         magnification := magnification / 2.0;
  2012.                         divisor := 4
  2013.                     end;
  2014.             end;
  2015.         with Info^.SrcRect, info^ do begin
  2016.                 width := round((right - left) * OldMagnification / Magnification);
  2017.                 height := round((bottom - top) * OldMagnification / Magnification);
  2018.                 left := left - (width div divisor);
  2019.                 if left < 0 then
  2020.                     left := 0;
  2021.                 if (left + width) > Info^.PicRect.right then
  2022.                     left := Info^.PicRect.right - round(width);
  2023.                 top := top - (height div divisor);
  2024.                 if top < 0 then
  2025.                     top := 0;
  2026.                 if (top + height) > Info^.PicRect.bottom then
  2027.                     top := Info^.picRect.bottom - round(height);
  2028.                 right := left + width;
  2029.                 bottom := top + height;
  2030.                 if magnification = 1.0 then
  2031.                     SrcRect := wrect;
  2032.                 RoiShowing := false;
  2033.                 UpdatePicWindow;
  2034.                 DrawMyGrowIcon(wptr);
  2035.             end;
  2036.         ShowRoi;
  2037.     end;
  2038.  
  2039.  
  2040.  
  2041.     procedure ZoomImageWindow; {(var trect: rect)}
  2042.         var
  2043.             WindowLeft, WindowTop: integer;
  2044.             PicAspectRatio, TempMagnification: extended;
  2045.     begin
  2046.         with info^ do begin
  2047.                 SrcRect := PicRect;
  2048.                 with CGrafPort(wptr^).PortPixMap^^.bounds do begin
  2049.                         WindowLeft := -left;
  2050.                         WindowTop := -top;
  2051.                     end;
  2052.                 with PicRect do
  2053.                     PicAspectRatio := right / bottom;
  2054.                 with trect do begin
  2055.                         if (WindowLeft + right) > (ScreenWidth - 5) then
  2056.                             right := ScreenWidth - 5 - WindowLeft;
  2057.                         bottom := round(right / PicAspectRatio);
  2058.                         if (WindowTop + bottom) > (ScreenHeight - 5) then
  2059.                             bottom := ScreenHeight - 5 - WindowTop;
  2060.                         right := round(bottom * PicAspectRatio);
  2061.                         magnification := right / PicRect.right;
  2062.                     end;
  2063.                 RoiRect := osroiRect;
  2064.                 OffscreenToScreenRect(RoiRect);
  2065.             end; {with}
  2066.     end;
  2067.  
  2068.  
  2069.     procedure DoGrow; {(WhichWindow: WindowPtr; event: EventRecord)}
  2070.         var
  2071.             NewSize: LongInt;
  2072.             tPort: GrafPtr;
  2073.             trect, WinRect: rect;
  2074.             ZoomCenterH, ZoomCenterV, width, height, imag, kind: integer;
  2075.     begin
  2076.         kind := WindowPeek(WhichWindow)^.WindowKind;
  2077.         if (kind = PicKind) and (info^.PictureType = ScionType) then
  2078.             exit(DoGrow);
  2079.         NewSize := GrowWindow(WhichWindow, event.where, ScreenBits.bounds);
  2080.         if newSize = 0 then
  2081.             exit(DoGrow);
  2082.         if WindowPeek(WhichWindow)^.WindowKind = PicKind then
  2083.             with Info^ do begin
  2084.                     InvalRect(wrect);
  2085.                     with trect do begin
  2086.                             top := 0;
  2087.                             left := 0;
  2088.                             right := LoWord(NewSize);
  2089.                             bottom := HiWord(NewSize);
  2090.                             if PictureType = camera then begin
  2091.                                     GetWindowRect(WhichWindow, WinRect);
  2092.                                     if WinRect.left + right + 4 > ScreenWidth then
  2093.                                         right := ScreenWidth - WinRect.left - 4;
  2094.                                     if WinRect.top + bottom + 4 > ScreenHeight then
  2095.                                         bottom := ScreenHeight - WinRect.top - 4;
  2096.                                 end;
  2097.                         end;
  2098.                     if ScaleToFitWindow then begin
  2099.                             ZoomImageWindow(trect);
  2100.                             wrect := trect;
  2101.                         end
  2102.                     else begin
  2103.                             imag := trunc(magnification);
  2104.                             if imag < 1 then
  2105.                                 imag := 1;
  2106.                             if trect.right > PicRect.right * imag then
  2107.                                 trect.right := PicRect.right * imag;
  2108.                             if trect.bottom > PicRect.bottom * imag then
  2109.                                 trect.bottom := PicRect.bottom * imag;
  2110.                             wrect := trect;
  2111.                             with SrcRect do begin
  2112.                                     ZoomCenterH := left + round((wrect.right div 2) / magnification);
  2113.                                     ZoomCenterV := top + round((wrect.bottom div 2) / magnification);
  2114.                                     width := wrect.right div imag;
  2115.                                     height := wrect.bottom div imag;
  2116.                                     left := ZoomCenterH - width div 2;
  2117.                                     if left < 0 then
  2118.                                         left := 0;
  2119.                                     if (left + width) > PicRect.right then
  2120.                                         left := PicRect.right - width;
  2121.                                     top := ZoomCenterV - height div 2;
  2122.                                     if top < 0 then
  2123.                                         top := 0;
  2124.                                     if (top + height) > PicRect.bottom then
  2125.                                         top := picRect.bottom - height;
  2126.                                     right := left + width;
  2127.                                     bottom := top + height;
  2128.                                 end;
  2129.                         end;
  2130.                     SizeWindow(WhichWindow, trect.right, trect.bottom, true);
  2131.                     exit(DoGrow)
  2132.                 end;
  2133.         if WhichWindow = PlotWindow then begin
  2134.                 PlotWidth := LoWord(NewSize);
  2135.                 PlotHeight := hiWord(NewSize);
  2136.                 SizeWindow(PlotWindow, PlotWidth, Plotheight, true);
  2137.                 GetPort(tPort);
  2138.                 SetPort(PlotWindow);
  2139.                 InvalRect(PlotWindow^.PortRect);
  2140.                 SetPort(tPort);
  2141.             end;
  2142.     end;
  2143.  
  2144.  
  2145.     procedure Zoom; {(event: EventRecord)}
  2146.         var
  2147.             width, height, OldMagnification: extended;
  2148.             PicCenterH, PicCenterV: integer;
  2149.     begin
  2150.         if Info = NoInfo then begin
  2151.                 beep;
  2152.                 exit(Zoom)
  2153.             end;
  2154.         if Info^.ScaleToFitWindow then begin
  2155.                 PutMessage('Zooming does not work in "Scale to Fit Window" mode.', '', '');
  2156.                 exit(Zoom)
  2157.             end;
  2158.         if BitAnd(Event.modifiers, OptionKey) = OptionKey then begin
  2159.                 DeZoom;
  2160.                 WhatToUndo := NothingToUndo;
  2161.                 exit(Zoom)
  2162.             end;
  2163.         with Info^ do begin
  2164.                 OldMagnification := magnification;
  2165.                 if magnification = 1.0 then
  2166.                     magnification := 2.0
  2167.                 else if magnification = 2.0 then
  2168.                     magnification := 3.0
  2169.                 else if magnification = 3.0 then
  2170.                     magnification := 4.0
  2171.                 else begin
  2172.                         magnification := magnification * 2.0;
  2173.                         if magnification > 64.0 then begin
  2174.                                 magnification := 64.0;
  2175.                                 exit(Zoom)
  2176.                             end;
  2177.                     end;
  2178.             end; {with}
  2179.         with Info^.SrcRect, Info^ do begin
  2180.                 PicCenterH := left + round(event.where.h / OldMagnification);
  2181.                 PicCenterV := top + round(event.where.v / OldMagnification);
  2182.                 width := wrect.right / magnification;
  2183.                 height := wrect.bottom / magnification;
  2184.                 left := PicCenterH - round(width / 2);
  2185.                 if left < 0 then
  2186.                     left := 0;
  2187.                 if (left + width) > PicRect.right then
  2188.                     left := PicRect.right - round(width);
  2189.                 top := PicCenterV - round(height / 2);
  2190.                 if top < 0 then
  2191.                     top := 0;
  2192.                 if (top + height) > PicRect.bottom then
  2193.                     top := picRect.bottom - round(height);
  2194.                 right := left + round(width);
  2195.                 bottom := top + round(height);
  2196.                 RoiShowing := false;
  2197.                 UpdatePicWindow;
  2198.                 DrawMyGrowIcon(wptr);
  2199.             end;
  2200.         WhatToUndo := UndoZoom;
  2201.         ShowRoi;
  2202.     end;
  2203.  
  2204.  
  2205.     procedure Scroll; {(event: EventRecord)}
  2206.         var
  2207.             hstart, vstart, DeltaH, DeltaV, width, height: integer;
  2208.             loc: point;
  2209.             SaveSrcRect: rect;
  2210.     begin
  2211.         if info^.ScaleToFitWindow then begin
  2212.                 PutMessage('Scrolling does not work in "Scale to Fit Window" mode.', '', '');
  2213.                 exit(Scroll)
  2214.             end;
  2215.         with event.where do begin
  2216.                 hstart := h;
  2217.                 vstart := v
  2218.             end;
  2219.         with Info^.SrcRect do begin
  2220.                 width := right - left;
  2221.                 height := bottom - top
  2222.             end;
  2223.         SaveSrcRect := Info^.SrcRect;
  2224.         while StillDown do begin
  2225.                 GetMouse(loc);
  2226.                 DeltaH := hstart - loc.h;
  2227.                 DeltaV := vstart - loc.v;
  2228.                 with Info^ do begin
  2229.                         with SrcRect do begin
  2230.                                 left := SaveSrcRect.left + DeltaH;
  2231.                                 if left < 0 then
  2232.                                     left := 0;
  2233.                                 if (left + width) > PicRect.right then
  2234.                                     left := PicRect.right - width;
  2235.                                 right := left + width;
  2236.                                 top := SaveSrcRect.top + DeltaV;
  2237.                                 if top < 0 then
  2238.                                     top := 0;
  2239.                                 if (top + height) > PicRect.bottom then
  2240.                                     top := PicRect.bottom - height;
  2241.                                 bottom := top + height;
  2242.                             end;
  2243.                         UpdatePicWindow;
  2244.                         DrawMyGrowIcon(wptr);
  2245.                     end;
  2246.             end;
  2247.         WhatToUndo := NothingToUndo;
  2248.         ShowRoi;
  2249.     end;
  2250.  
  2251.  
  2252.     procedure ConvertClipboard;
  2253. {Converts local scrape to system scrape. Used when quiting or}
  2254. {switching to other programs or DAs . }
  2255.         var
  2256.             PicH: PicHandle;
  2257.             PicRect, frect: rect;
  2258.             tPort, sPort: GrafPtr;
  2259.             SaveClipRgn: RgnHandle;
  2260.             err: LongInt;
  2261.     begin
  2262.         PicH := nil;
  2263.         if (WhatsOnClip = RectPic) and (ClipBuf <> nil) and not ClipboardConverted then
  2264.             with ClipBufInfo^ do begin
  2265.                     ShowWatch;
  2266.                     sPort := GrafPtr(CScreenPort);
  2267.                     GetPort(tPort);
  2268.                     SetPort(sPort);
  2269.                     with sPort^ do begin
  2270.                             SaveClipRgn := ClipRgn;
  2271.                             ClipRgn := NewRgn;
  2272.                             SetRectRgn(ClipRgn, -30000, -30000, 30000, 30000);
  2273.                             with osroiRect do
  2274.                                 SetRect(frect, 0, 0, right - left, bottom - top);
  2275.                             LoadLUT(ctable);
  2276.                             PicH := OpenPicture(frect);
  2277.                             hlock(handle(osPort^.portPixMap));
  2278.                             hlock(handle(CGrafPort(ThePort^).PortPixMap));
  2279.                             CopyBits(BitMapHandle(osPort^.portPixMap)^^, BitMapHandle(CGrafPort(ThePort^).PortPixMap)^^, osroiRect, frect, SrcCopy, nil);
  2280.                             hunlock(handle(osPort^.portPixMap));
  2281.                             hunlock(handle(CGrafPort(ThePort^).PortPixMap));
  2282.                             ClosePicture;
  2283.                             DisposeRgn(clipRgn);
  2284.                             clipRgn := SaveClipRgn;
  2285.                         end;
  2286.                     SetPort(tPort);
  2287.                 end;
  2288.         if (PicH <> nil) or TextOnClip then begin
  2289.                 err := ZeroScrap;
  2290.                 if err = NoErr then begin
  2291.                         if PicH <> nil then begin
  2292.                                 hlock(handle(PicH));
  2293.                                 err := PutScrap(GetHandleSize(handle(PicH)), 'PICT', handle(PicH)^);
  2294.                                 hunlock(handle(PicH));
  2295.                                 DisposHandle(handle(PicH));
  2296.                             end;
  2297.                         if TextOnClip and (err = noErr) then
  2298.                             err := PutScrap(TextBufSize, 'TEXT', ptr(TextBufP));
  2299.                     end;
  2300.             end;
  2301.         ClipboardConverted := true;
  2302.     end;
  2303.  
  2304.  
  2305.     procedure SetupOperation; {(item: integer)}
  2306.         var
  2307.             AutoSelectAll: boolean;
  2308.     begin
  2309.         if NotinBounds then
  2310.             exit(SetupOperation);
  2311.         if (item = 10) then
  2312.             if NoSelection then
  2313.                 exit(SetupOperation);
  2314.         StopDigitizing;
  2315.         AutoSelectAll := not Info^.RoiShowing;
  2316.         if AutoSelectAll then
  2317.             SelectAll(true);
  2318.         SetupUndo;
  2319.         WhatToUndo := UndoEdit;
  2320.         case Item of
  2321.             8: 
  2322.                 begin
  2323.                     CurrentOp := PaintOp;
  2324.                     OpPending := true
  2325.                 end;
  2326.             9: 
  2327.                 begin
  2328.                     CurrentOp := InvertOp;
  2329.                     OpPending := true
  2330.                 end;
  2331.             10: 
  2332.                 begin
  2333.                     CurrentOp := FrameOp;
  2334.                     OpPending := true
  2335.                 end;
  2336.         end;
  2337.         if AutoSelectAll then
  2338.             KillRoi;
  2339.     end;
  2340.  
  2341.  
  2342. end.